#include "ikvm_video.hpp"

#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/elog.hpp>
#include <phosphor-logging/log.hpp>
#include <xyz/openbmc_project/Common/Device/error.hpp>
#include <xyz/openbmc_project/Common/File/error.hpp>

namespace ikvm
{

	const int Video::bitsPerSample(8);
	const int Video::bytesPerPixel(4);
	const int Video::samplesPerPixel(3);

	using namespace phosphor::logging;
	using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
	using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error;

	extern "C"
	{
		#include "device.h"
		extern void us_device_set_param(void *param, char *path, int width, int height, int frameRate);
		extern char *us_device_get_data(void *hw);
		extern int us_device_get_datalen(void *hw);
		extern int us_device_get_rate(void *hw) ;
		extern size_t us_device_get_size(void *hw);
		extern size_t us_device_get_height(void *hw)  ;   
		extern size_t us_device_get_width(void *hw) ;    
		extern int us_device_get_format(void *hw);
		extern int us_device_release_buffer(void *p, void  *p1);
		extern int us_device_grab_buffer(void *p, void **p1) ;
		extern int us_device_switch_capturing(void *p, bool enable);
	}
#define DEBUG(fmt, arg...)  printf("[%s.%d]" fmt "\n", __FUNCTION__,__LINE__, ##arg);	
	Video::Video(const std::string& p, int fr, int sub, int w, int h) 
	{
		DEBUG("SSS1 call create Video");
		path = p;
		resizeAfterOpen=false;
		timingsError = false;
		fd = -1;
		frameRate =fr;
		lastFrameIndex=-1;
		height = h;
		width = w;
		subSampling =sub;
		pDevice = us_device_init(); 
		us_device_set_param(pDevice, (char*)path.c_str(), width,  height, fr);
	}

	Video::~Video()
	{
		DEBUG("SSS1 call stop video");
	    _stop();
	}
	int Video::getFrameRate() 
	{
//		DEBUG("SSS1 call getFrameRate video");
	    return frameRate;//us_device_get_rate(hw);
	}
	unsigned int Video::getFrameSize() 
	{
//		DEBUG("SSS1 call getFrameSize video");
	    return (unsigned int)us_device_get_size(hw);
	}
	unsigned int Video::getHeight() 
	{
//		DEBUG("SSS1 call getHeight video");
	    return height;//(unsigned int)us_device_get_height(hw);
	}
	unsigned int Video::getWidth() 
	{
//		DEBUG("SSS1 call getWidth video");
	    return width;//(unsigned int)us_device_get_width(hw);
	}

	char* Video::getData(int index)
	{
//		DEBUG("SSS1 call getData video");
	   return us_device_get_data(hw);
	}

	int Video::getFrame()
	{	
//		DEBUG("SSS1 call getFrame video");
		bool has_read = false;
		bool has_write = false;
		bool has_error = false;
		if(us_device_select(pDevice,  &has_read, &has_write, &has_error) >=0 && has_read)
		{
			return us_device_grab_buffer(pDevice,  &hw);
		}
		else
		{
			return -1;
		}
	}
	void Video::freeFrame(int index)
	{
//		DEBUG("SSS1 call freeFrame video");
		us_device_release_buffer(pDevice, hw) ;
	}

	bool Video::needsResize()
	{
//		DEBUG("SSS1 call needsResize video");
	    return false;
	}

	void Video::resize()
	{
//		DEBUG("SSS1 call resize video");
	    return ;
	}

	int Video::start()
	{
		if(this->fd > 0)
			return 1;
		DEBUG("SSS1 tangqi call start video");
		us_device_open(pDevice);
		us_device_switch_capturing(pDevice, true);
		this->fd = 1;
		return 0;
	}
	void Video::stop()
	{
		if(this->fd == 0)
			return ;
		DEBUG("SSS1 call stop video");
		us_device_switch_capturing(pDevice, false);
		us_device_close(pDevice);
		this->fd = 0;
	}
	void Video::_stop()
	{
		
	}

} // namespace ikvm
